#include "pyGoCommunicationManager.h"
PyGoCommunicationManager::PyGoCommunicationManager(WaveListModel *wlm, ARBlipArray *arba)
{
    m_waveListModel = wlm;
    m_ARBlips = arba;
    m_controller = new PyGoWave::Controller();
    connect(m_controller, SIGNAL(waveAdded(QByteArray,bool,bool)), this, SLOT(controller_waveAdded(QByteArray)));
    connect(m_controller, SIGNAL(waveAboutToBeRemoved(QByteArray)), this, SLOT(controller_waveAboutToBeRemoved(QByteArray)));
}

/*
PyGoCommunicationManager::~PyGoCommunicationManager()
{
    //????
    delete m_controller;
}
*/

void PyGoCommunicationManager::login(QString serverAddress, QString username, QString password, int port)
{
    m_controller->connectToHost(serverAddress, username, password, port); 
}

void PyGoCommunicationManager::logout()
{
    m_controller->disconnectFromHost();
}

void PyGoCommunicationManager::createWave(QString title)
{
    m_controller->createNewWave(title);
}

void PyGoCommunicationManager::openWavelet(QString waveID)
{
    QByteArray waveletID = m_controller->wave(waveID.toLatin1())->rootWavelet()->id();
    //get the current wavelet handle
    m_currentWavelet = m_controller->wavelet( waveletID );
    //request to open it
    m_controller->openWavelet( waveletID );

    //stay tuned for when the wavelet is opened
    connect(m_controller, SIGNAL(waveletOpened(QByteArray,bool)), this, SLOT(controller_waveletOpened(QByteArray,bool)));

    //listen for wavelet changes (new blip inserted by another client for example)
    connect(m_currentWavelet, SIGNAL(blipInserted(int, const QByteArray)), this, SLOT(wavelet_blipInserted(int, const QByteArray)));
    connect(m_currentWavelet, SIGNAL(blipDeleted(QByteArray)), this, SLOT(wavelet_blipDeleted(QByteArray)));
}

void PyGoCommunicationManager::closeWavelet()
{
    m_controller->closeWavelet( m_currentWavelet->id() );
}

void PyGoCommunicationManager::controller_waveAdded(const QByteArray &waveId)//, bool created, bool initial)
{
    //get the last existing row
    int lastRow = m_waveListModel->rowCount(QModelIndex());
    //add a new row at the end of the list
    m_waveListModel->insertRows( m_waveListModel->rowCount(QModelIndex()), 1); //insert just one row
    //create a new waveModel object
    WaveModel *wave = new WaveModel( QString(waveId), QDateTime::currentDateTime(), QString("Placeholder"));
    QVariant newWave;
    newWave.setValue(wave);
    //get the index of the last added element
    QModelIndex modelIndex = m_waveListModel->index( lastRow, 0, QModelIndex());
    //put the new wave at the right place
    m_waveListModel->setData(modelIndex, newWave, Qt::EditRole);
}

void PyGoCommunicationManager::controller_waveAboutToBeRemoved(const QByteArray &waveId)
{
    //TODO: also, is this needed?
}

void PyGoCommunicationManager::controller_waveletOpened(const QByteArray &waveletID, bool isRoot)
{
    QList<PyGoWave::Blip *> blips = m_currentWavelet->allBlips();
    for(int i = 0; i < blips.size(); i++)
    {
        connect(blips.at(i), SIGNAL(insertedText(int, const QString &)), this, SLOT(blip_insertedText(int, const QString &)));
        connect(blips.at(i), SIGNAL(deletedText(int, int)), this, SLOT(blip_deletedText(int, int)));
    }
}

void PyGoCommunicationManager::wavelet_blipInserted(int index, QByteArray blipID)
{
    //if this is not a temp id
    if( !blipID.startsWith("TBD") )
    {
        PyGoWave::Blip *blip = m_currentWavelet->blipById( blipID );
        connect( blip, SIGNAL(insertedText(int,QString)), this, SLOT(blip_insertedText(int,QString)) );
        connect( blip, SIGNAL(deletedText(int,int)), this, SLOT(blip_deletedText(int,int)) );
        updateARBlipArray(blip);
    }
    else
    {
        //otherwise there's anothere thing we need to do with temp blips
        //listen for when the real blipID is returned by the server
        connect(m_currentWavelet->blipById( blipID ), SIGNAL(idChanged(QByteArray,QByteArray)), this, SLOT(blip_IDChanged(QByteArray,QByteArray)));
    }
}

void PyGoCommunicationManager::wavelet_blipDeleted(QByteArray blipID)
{
    //delete the arblip form the list
    m_ARBlips->removeARBlipByID( blipID );
    //notify the rest of the world
    emit arblipsUpdated();
}

void PyGoCommunicationManager::blip_IDChanged(QByteArray oldID, QByteArray newID)
{
    PyGoWave::Blip *blip = m_currentWavelet->blipById( newID );
    connect( blip, SIGNAL(insertedText(int,QString)), this, SLOT(blip_insertedText(int,QString)) );
    connect( blip, SIGNAL(deletedText(int,int)), this, SLOT(blip_deletedText(int,int)) );
    updateARBlipArray( blip );
}

void PyGoCommunicationManager::addBlip(QString text)
{
    //create a new blip
    m_controller->appendBlip( m_currentWavelet->id() );
    //FIXME: this could probably be done with lot less code...
    //fill the blip with the needed infos
    QList<PyGoWave::Blip *> allBlips = m_currentWavelet->allBlips();
    //FIXME: will this work on concurrent update? how to avoid this problem?
    PyGoWave::Blip *blip = allBlips.at( allBlips.size() - 1 );
    //FIXME: use the real participant
    PyGoWave::Participant *p = new PyGoWave::Participant("");
    blip->insertText(0, text, p, false);
    //"confirm" insertion
    m_controller->textInserted(m_currentWavelet->id(), blip->id(), 0, text);
}

void PyGoCommunicationManager::updateBlip(QByteArray blipID, QString text)
{
    PyGoWave::Blip *blip = m_currentWavelet->blipById( blipID );
    m_controller->textDeleted(m_currentWavelet->id(), blipID, 0, blip->content().length());
    m_controller->textInserted(m_currentWavelet->id(), blipID, 0, text);
}

//react to changes in the blips;
//FIXME: this is called automatically by the controller, and it's called too often
//(almost one time for every single char, this is quite too much for us i guess...)
void PyGoCommunicationManager::blip_deletedText(int index, int lenght)
{
    const PyGoWave::Blip *blip = static_cast<const PyGoWave::Blip *>( sender() );
    updateARBlipArray( blip );
}

//react to changes in the blips;
//FIXME: this is called automatically by the controller, and it's called too often
//(almost one time for every single char, this is quite too much for us i guess...)
void PyGoCommunicationManager::blip_insertedText(int index, const QString &text)
{
    const PyGoWave::Blip *blip = static_cast<const PyGoWave::Blip *>( sender() );
    updateARBlipArray( blip );
}

void PyGoCommunicationManager::updateARBlipArray(const PyGoWave::Blip *blip)
{
    //crate a new arblip from the blip
    ARBlip *newARBlip = new ARBlip();
    //fill arblip infos
    newARBlip->loadFromString( blip->content() );
    //set arblip id (same as blip id)
    newARBlip->setReferanceID( blip->id());
    //add (or replace) the new blip
    m_ARBlips->addBlip( *newARBlip );

    //notify the rest of the world
    emit arblipsUpdated();
}

void PyGoCommunicationManager::deleteBlip(QByteArray blipID)
{
    m_controller->deleteBlip( m_currentWavelet->id(), blipID );
}

bool PyGoCommunicationManager::addParticipant(QString participant)
{
    if( m_currentWavelet->allParticipantIDs().contains( participant.toLatin1() ) )
    {
        return false;
    }

    m_controller->addParticipant( m_currentWavelet->id(), participant.toLatin1() );
    return true;
}
